﻿using Core.Info;
using Core.Log;
using Core.Utility.Cache;
using Core.Utility.Config;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Core.Utility.Helper
{
    /// <summary>
    /// Json配置助手类
    /// 文件配置规则：data.section.data.value 存储到文件为base64后的字符串
    /// </summary>
    public static class JsonConfigHelper
    {
        /// <summary>
        /// 默认文件后缀名
        /// </summary>
        public const string DEFAULT_FILE_SUFFIX = ".config.json";

        /// <summary>
        /// 配置目录：应用根目录/Cache/
        /// </summary>
        public static string ConfigDirectory { get; private set; }

        /// <summary>
        /// 默认构造`
        /// </summary>
        static JsonConfigHelper()
        {
            ConfigDirectory = Path.Combine(AppInfo.ConfigDirectory);
            if (!Directory.Exists(ConfigDirectory))
            {
                Directory.CreateDirectory(ConfigDirectory);
            }
        }

        #region 读取
        /// <summary>
        /// 读取Json配置
        /// </summary>
        /// <param name="fileName">配置文件名，不含文件目录及扩展名</param>
        /// <param name="fileSuffix">配置文件扩展名，默认使用 <see cref="DEFAULT_FILE_SUFFIX"/></param>
        /// <param name="configAttachDirectory">配置附加目录，通常用于不同账号、租户间的配置目录区分</param>
        /// <returns></returns>
        public static JsonConfig? ReadJsonConfig(string fileName, string configAttachDirectory = "", string fileSuffix = DEFAULT_FILE_SUFFIX)
        {
            if (string.IsNullOrEmpty(configAttachDirectory))
            {
                configAttachDirectory = "";
            }
            string fileFullPath = Path.Combine(ConfigDirectory, configAttachDirectory, $"{fileName}{fileSuffix}");
            return ReadJsonConfigByFielFullPath(fileFullPath);
        }

        /// <summary>
        /// 读取Json配置,通过文件完整路径
        /// </summary>
        /// <param name="fileFullPath">配置文件全路径，包含文件所在的目录及扩展名</param>
        /// <returns></returns>
        public static JsonConfig? ReadJsonConfigByFielFullPath(string fileFullPath)
        {
            JsonConfig? res = DefaultJsonConfig();
            try
            {
                if (!File.Exists(fileFullPath))
                {
                    AppTrace.Logger.LogInformation($"读取JSON配置文件不存，配置路径：\r\n{fileFullPath}\r\n将使用默认值加载！");
                    FileHelper.WriteFileReturnBool(fileFullPath, JsonHelper.Serialize(DefaultJsonConfig()));
                }
                string? fileJsonString = FileHelper.ReadFileToString(fileFullPath);
                res = JsonHelper.Deserialize<JsonConfig>(fileJsonString);
                res = res?.JsonConfigValueConverter(JsonConfigValueOperation.Base64StringToString);
            }
            catch (Exception ex)
            {
                AppTrace.Logger.LogError(ex, $"读取JSON配置出错，配置路径：\r\n{fileFullPath}\r\n这可能是因为配置文件内容不合法,将使用默认值加载！");
            }
            return res;
        }
        #endregion 读取

        #region 保存
        /// <summary>
        /// 保存Json配置
        /// </summary>
        /// <param name="jsonConfig"></param>
        /// <param name="fileName">配置文件名，不含文件目录及扩展名</param>
        /// <param name="configAttachDirectory">配置附加目录，通常用于不同账号、租户间的配置目录区分</param>
        /// <param name="fileSuffix">配置文件扩展名，默认使用 <see cref="DEFAULT_FILE_SUFFIX"/></param>
        /// <returns></returns>
        public static bool SaveJsonConfig(this JsonConfig jsonConfig, string fileName, string configAttachDirectory = "", string fileSuffix = DEFAULT_FILE_SUFFIX)
        {
            string message = "";
            if (string.IsNullOrEmpty(configAttachDirectory))
            {
                configAttachDirectory = "";
            }
            string fileFullPath = Path.Combine(ConfigDirectory, configAttachDirectory, $"{fileName}{fileSuffix}");
            return SaveJsonConfigByFielFullPath(jsonConfig,fileFullPath,out message);
        }

        /// <summary>
        /// 保存Json配置 通过文件完整路径
        /// </summary>
        /// <param name="jsonConfig"></param>
        /// <param name="fileFullPath">配置文件全路径，包含文件所在的目录及扩展名</param>
        /// <param name="message">保存的消息提示</param>
        /// <returns></returns>
        public static bool SaveJsonConfigByFielFullPath(this JsonConfig jsonConfig, string fileFullPath,out string message)
        {
            bool res = false;
            try
            {
                var saveJsonConfig = jsonConfig.DeepCopyByJson();
                saveJsonConfig = saveJsonConfig.JsonConfigValueConverter();
                res = FileHelper.WriteFileReturnBool(fileFullPath, JsonHelper.Serialize(saveJsonConfig));
                message = "操作成功";
            }
            catch (Exception ex)
            {
                message = $"保存JSON配置出错，配置路径：\r\n{fileFullPath}\r\n";
                AppTrace.Logger.LogError(ex, message);
                throw new Exception(message, ex);
            }
            return res;
        }
        #endregion 保存

        #region 获取配置
        /// <summary>
        /// 获取Json配置
        /// </summary>
        /// <param name="fileName">配置文件名，不含文件目录及扩展名</param>
        /// <param name="fileSuffix">配置文件扩展名，默认使用 <see cref="DEFAULT_FILE_SUFFIX"/></param>
        /// <param name="section">配置节，不区分大小写</param>
        /// <param name="key">配置节的key，不区分大小写</param>
        /// <param name="defaultValue">获取配置的默认值</param>
        /// <param name="configAttachDirectory">配置附加目录，通常用于不同账号、租户间的配置目录区分</param>
        /// <returns></returns>
        public static string? GetJsonConfig(string fileName, string section, string key, string defaultValue = "", string configAttachDirectory = "", string fileSuffix = DEFAULT_FILE_SUFFIX)
        {
            return GetJsonConfig<string>(fileName, section, key, defaultValue, configAttachDirectory, fileSuffix);
        }

        /// <summary>
        /// 获取Json配置
        /// </summary>
        /// <param name="fileName">配置文件名，不含文件目录及扩展名</param>
        /// <param name="fileSuffix">配置文件扩展名，默认使用 <see cref="DEFAULT_FILE_SUFFIX"/></param>
        /// <param name="section">配置节，不区分大小写</param>
        /// <param name="key">配置节的key，不区分大小写</param>
        /// <param name="defaultValue">获取配置的默认值</param>
        /// <param name="configAttachDirectory">配置附加目录，通常用于不同账号、租户间的配置目录区分</param>
        /// <returns></returns>
        public static T? GetJsonConfig<T>(string fileName, string section, string key, T? defaultValue = default(T), string configAttachDirectory = "", string fileSuffix = DEFAULT_FILE_SUFFIX)
        {
            if (string.IsNullOrEmpty(configAttachDirectory))
            {
                configAttachDirectory = "";
            }
            string fileFullPath = Path.Combine(ConfigDirectory, configAttachDirectory, $"{fileName}{fileSuffix}");
            return GetJsonConfigByFileFullPath<T>(fileFullPath,section,key,defaultValue);
        }

        /// <summary>
        /// 获取Json配置
        /// </summary>
        /// <param name="fileName">配置文件名，不含文件目录及扩展名</param>
        /// <param name="fileSuffix">配置文件扩展名，默认使用 <see cref="DEFAULT_FILE_SUFFIX"/></param>
        /// <param name="section">配置节，不区分大小写</param>
        /// <param name="configAttachDirectory">配置附加目录，通常用于不同账号、租户间的配置目录区分</param>
        /// <returns></returns>
        public static JsonConfigSection GetJsonConfigSection(string fileName, string section, string configAttachDirectory = "", string fileSuffix = DEFAULT_FILE_SUFFIX)
        {
            if (string.IsNullOrEmpty(configAttachDirectory))
            {
                configAttachDirectory = "";
            }
            string fileFullPath = Path.Combine(ConfigDirectory, configAttachDirectory, $"{fileName}{fileSuffix}");
            return GetJsonConfigSectionByFileFullPath(fileFullPath, section);
        }

        /// <summary>
        /// 获取Json配置
        /// </summary>
        /// <param name="fileName">配置文件名，不含文件目录及扩展名</param>
        /// <param name="fileSuffix">配置文件扩展名，默认使用 <see cref="DEFAULT_FILE_SUFFIX"/></param>
        /// <param name="section">配置节，不区分大小写</param>
        /// <param name="configAttachDirectory">配置附加目录，通常用于不同账号、租户间的配置目录区分</param>
        /// <returns></returns>
        public static List<JsonConfigSectionItem> GetJsonConfigSectionItems(string fileName, string section, string configAttachDirectory = "", string fileSuffix = DEFAULT_FILE_SUFFIX)
        {
            if (string.IsNullOrEmpty(configAttachDirectory))
            {
                configAttachDirectory = "";
            }
            string fileFullPath = Path.Combine(ConfigDirectory, configAttachDirectory, $"{fileName}{fileSuffix}");
            return GetJsonConfigSectionItemsByFileFullPath(fileFullPath, section);
        }
        #endregion 获取配置

        #region 获取配置 - 通过文件全路径
        /// <summary>
        /// 获取Json配置，通过文件全路径
        /// </summary>
        /// <param name="fileFullPath">配置文件名，全路径，包含文件所在的目录及扩展名</param>
        /// <param name="section">配置节，不区分大小写</param>
        /// <returns></returns>
        public static JsonConfigSection GetJsonConfigSectionByFileFullPath(string fileFullPath, string section)
        {
            JsonConfigSection res = new JsonConfigSection();
            if (File.Exists(fileFullPath) && !string.IsNullOrEmpty(section))
            {
                JsonConfig? jsonConfig = ReadJsonConfigByFielFullPath(fileFullPath);
                if (jsonConfig != null)
                {
                    var findCacheSection = jsonConfig?.Data?.FirstOrDefault(p => p.Section == section);
                    if (findCacheSection != null)
                    {
                        res = findCacheSection;
                    }
                }
            }
            return res;
        }

        /// <summary>
        /// 获取Json配置，通过文件全路径
        /// </summary>
        /// <param name="fileFullPath">配置文件名，全路径，包含文件所在的目录及扩展名</param>
        /// <param name="section">配置节，不区分大小写</param>
        /// <returns></returns>
        public static List<JsonConfigSectionItem> GetJsonConfigSectionItemsByFileFullPath(string fileFullPath, string section)
        {
            List<JsonConfigSectionItem>? res = null;
            res = GetJsonConfigSectionByFileFullPath(fileFullPath, section)?.Item;
            if(res == null)
            {
                res = new List<JsonConfigSectionItem>();
            }
            return res;
        }

        /// <summary>
        /// 获取Json配置，通过文件全路径
        /// </summary>
        /// <param name="fileFullPath">配置文件名，全路径，包含文件所在的目录及扩展名</param>
        /// <param name="section">配置节，不区分大小写</param>
        /// <param name="key">配置节的key，不区分大小写</param>
        /// <param name="defaultValue">获取配置的默认值</param>
        /// <returns></returns>
        public static string? GetJsonConfigByFileFullPath(string fileFullPath, string section, string key, string defaultValue = "")
        {
            return GetJsonConfigByFileFullPath<string>(fileFullPath, section, key, defaultValue);
        }


        /// <summary>
        /// 获取Json配置，通过文件全路径
        /// </summary>
        /// <param name="fileFullPath">配置文件名，全路径，包含文件所在的目录及扩展名</param>
        /// <param name="section">配置节，不区分大小写</param>
        /// <param name="key">配置节的key，不区分大小写</param>
        /// <param name="defaultValue">获取配置的默认值</param>
        /// <returns></returns>
        public static T? GetJsonConfigByFileFullPath<T>(string fileFullPath, string section, string key, T? defaultValue = default(T))
        {
            T? res = defaultValue;
            var jsonConfigSectionItems = GetJsonConfigSectionItemsByFileFullPath(fileFullPath, section);
            if (jsonConfigSectionItems?.Count() > 0)
            {
                var jsonConfigSectionItem = jsonConfigSectionItems?.FirstOrDefault(p => p.Key == key);
                if (jsonConfigSectionItem != null)
                {
                    string? content = jsonConfigSectionItem?.Content;
                    res = ValueTypeConvertHelper.ChangeType(content, defaultValue);
                }
            }
            return res;
        }
        #endregion 获取配置 - 通过文件全路径


        /// <summary>
        /// 设置Json配置
        /// </summary>
        /// <param name="fileName">配置文件名，不含文件目录及扩展名</param>
        /// <param name="fileSuffix">配置文件扩展名，默认使用 <see cref="DEFAULT_FILE_SUFFIX"/></param>
        /// <param name="section">配置节，不区分大小写</param>
        /// <param name="key">配置节的key，不区分大小写</param>
        /// <param name="value">设置配置的值</param>
        /// <param name="configAttachDirectory">配置附加目录，通常用于不同账号、租户间的配置目录区分</param>
        /// <returns></returns>
        public static bool SetJsonConfig(string fileName, string section, string key, string value, string configAttachDirectory = "", string fileSuffix = DEFAULT_FILE_SUFFIX)
        {
            if (string.IsNullOrEmpty(configAttachDirectory))
            {
                configAttachDirectory = "";
            }
            string fileFullPath = Path.Combine(ConfigDirectory, configAttachDirectory, $"{fileName}{fileSuffix}");
            return SetJsonConfigByFileFullPath(fileFullPath, section, key, value);
        }

        /// <summary>
        /// 设置Json配置，通过文件全路径
        /// </summary>
        /// <param name="fileFullPath">配置文件名，全路径，包含文件所在的目录及扩展名</param>
        /// <param name="section">配置节，不区分大小写,不能为空，否则抛出异常</param>
        /// <param name="value">设置配置的值</param>
        /// <returns></returns>
        public static bool SetJsonConfigSectionItemsByFileFullPath(string fileFullPath, string section, List<JsonConfigSectionItem>? value = null)
        {
            if (string.IsNullOrEmpty(section))
            {
                throw new ArgumentNullException(nameof(section), "参数不能为空");
            }
            if(value == null)
            {
                value = new List<JsonConfigSectionItem>();
            }
            bool res = false;
            JsonConfig? setJsonConfig = ReadJsonConfigByFielFullPath(fileFullPath);
            var findCacheSection = setJsonConfig?.Data?.FirstOrDefault(p => p?.Section == section);
            if (findCacheSection != null)
            {
                var findCacheSectionIndex = setJsonConfig?.Data?.IndexOf(findCacheSection);
                findCacheSection.Item = value;
                if (setJsonConfig != null && findCacheSectionIndex != null && findCacheSectionIndex > -1)
                {
#pragma warning disable CS8602 // 解引用可能出现空引用。
                    setJsonConfig.Data[findCacheSectionIndex.GetValueOrDefault(0)] = findCacheSection;
#pragma warning restore CS8602 // 解引用可能出现空引用。
                }
            }
            else
            {
                findCacheSection = new JsonConfigSection()
                {
                    Section = section,
                    Item = value
                };
                if (setJsonConfig == null)
                {
                    setJsonConfig = new JsonConfig();
                }
                if (setJsonConfig.Data == null)
                {
                    setJsonConfig.Data = new List<JsonConfigSection>()
                    {
                        findCacheSection
                    };
                }
                else
                {
                    setJsonConfig.Data.Add(findCacheSection);
                }
            }
#pragma warning disable CS8602 // 解引用可能出现空引用。
            setJsonConfig.UpdatedTime = AppTime.Now;
#pragma warning restore CS8602 // 解引用可能出现空引用。
            setJsonConfig.Revision = Guid.NewGuid().ToString();
            string message = "";
            res = setJsonConfig.SaveJsonConfigByFielFullPath(fileFullPath, out message);
            return res;
        }

        /// <summary>
        /// 设置Json配置，通过文件全路径
        /// </summary>
        /// <param name="fileFullPath">配置文件名，全路径，包含文件所在的目录及扩展名</param>
        /// <param name="section">配置节，不区分大小写,不能为空，否则抛出异常</param>
        /// <param name="key">配置节的key，不区分大小写,不能为空，否则抛出异常</param>
        /// <param name="value">设置配置的值</param>
        /// <returns></returns>
        public static bool SetJsonConfigByFileFullPath(string fileFullPath, string section, string key, string value = "")
        {
            return SetJsonConfigByFileFullPath<string>(fileFullPath, section, key, value);
        }

        /// <summary>
        /// 设置Json配置，通过文件全路径
        /// </summary>
        /// <param name="fileFullPath">配置文件名，全路径，包含文件所在的目录及扩展名</param>
        /// <param name="section">配置节，不区分大小写,不能为空，否则抛出异常</param>
        /// <param name="key">配置节的key，不区分大小写,不能为空，否则抛出异常</param>
        /// <param name="value">设置配置的值</param>
        /// <returns></returns>
        public static bool SetJsonConfigByFileFullPath<T>(string fileFullPath, string section, string key, T? value = default(T))
        {
            if (string.IsNullOrEmpty(section))
            {
                throw new ArgumentNullException(nameof(section), "参数不能为空");
            }
            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentNullException(nameof(key), "参数不能为空");
            }
            bool res = false;
            JsonConfig? setJsonConfig = ReadJsonConfigByFielFullPath(fileFullPath);
            var findCacheSection = setJsonConfig?.Data?.FirstOrDefault(p => p?.Section == section);
            if (findCacheSection != null)
            {
#pragma warning disable CS8602 // 解引用可能出现空引用。
                var findCacheSectionIndex = setJsonConfig.Data.IndexOf(findCacheSection);
#pragma warning restore CS8602 // 解引用可能出现空引用。
                var findData = findCacheSection?.Item?.FirstOrDefault(p => key == p.Key);
                if (findData != null)
                {
                    var findDataIndex = findCacheSection?.Item?.IndexOf(findData);
                    findData.Content = value?.ToString();
                    if (findCacheSection != null && findCacheSection.Item != null && findDataIndex != null)
                    {
                        findCacheSection.Item[findDataIndex.GetValueOrDefault(0)] = findData;
                    }
                }
                else
                {
                    findData = new JsonConfigSectionItem()
                    {
                        Key = key,
                        Content = value?.ToString(),
                    };
                    findCacheSection?.Item?.Add(findData);
                }
                if (findCacheSection != null)
                {
                    setJsonConfig.Data[findCacheSectionIndex] = findCacheSection;
                }
            }
            else
            {
                findCacheSection = new JsonConfigSection()
                {
                    Section = section,
                    Item = new List<JsonConfigSectionItem>()
                    {
                        new JsonConfigSectionItem()
                        {
                            Key = key,
                            Content = value?.ToString(),
                        }
                    }
                };
                if (setJsonConfig == null)
                {
                    setJsonConfig = new JsonConfig();
                }
                if (setJsonConfig.Data == null)
                {
                    setJsonConfig.Data = new List<JsonConfigSection>()
                    {
                        findCacheSection
                    };
                }
                else
                {
                    setJsonConfig.Data.Add(findCacheSection);
                }

            }
            setJsonConfig.UpdatedTime = AppTime.Now;
            setJsonConfig.Revision = Guid.NewGuid().ToString();
            string message = "";
            res = setJsonConfig.SaveJsonConfigByFielFullPath(fileFullPath, out message);
            return res;
        }

        /// <summary>
        /// Json配置值转换
        /// </summary>
        /// <param name="jsonConfig"></param>
        /// <param name="jsonConfigValueOperation">Json配置值操作，参照<see cref="JsonConfigValueOperation"/></param>
        /// <returns></returns>
        public static JsonConfig? JsonConfigValueConverter(this JsonConfig jsonConfig, JsonConfigValueOperation jsonConfigValueOperation = JsonConfigValueOperation.StringToBase64String)
        {
            JsonConfig? res = jsonConfig.DeepCopyByJson();
            if (res != null)
            {
                if(res?.Data?.Count > 0)
                {
                    var jsonConfigDataList = res.Data;
                    #region 遍历Json配置的数据节点
                    for (int iCacheData = 0; iCacheData < jsonConfigDataList.Count; iCacheData++)
                    {
                        var jsonConfigDataItem = jsonConfigDataList[iCacheData];
                        if (jsonConfigDataItem?.Item?.Count > 0)
                        {
                            #region 遍历Json配置数据节点的Section
                            for (int iSection = 0; iSection < jsonConfigDataItem.Item.Count; iSection++)
                            {
                                var jsonConfigDataSection = jsonConfigDataItem.Item[iSection];
                                if (jsonConfigValueOperation == JsonConfigValueOperation.Base64StringToString)
                                {
                                    jsonConfigDataSection.Content = ValueTypeConvertHelper.Base64StringToUtf8String(jsonConfigDataSection.Content);
                                }
                                else if (jsonConfigValueOperation == JsonConfigValueOperation.StringToBase64String)
                                {
                                    jsonConfigDataSection.Content = ValueTypeConvertHelper.ToUtf8Base64String(jsonConfigDataSection.Content);
                                }
                                jsonConfigDataItem.Item[iSection] = jsonConfigDataSection;
                            }
                            #endregion 遍历Json配置数据节点的Section 
                        }
                    }
                    #endregion 遍历Json配置的数据节点 
                }
            }
            return res;
        }

        /// <summary>
        /// 默认Json配置
        /// </summary>
        /// <returns></returns>
        private static JsonConfig DefaultJsonConfig()
        {
            return new JsonConfig()
            {
                CreatedTime = AppTime.Now,
                UpdatedTime = AppTime.Now,
                Revision = Guid.NewGuid().ToString(),
                Data = new List<JsonConfigSection>(),
            };
        }
    }
}
